# -*- coding: utf-8 -*-
"""
@ Created on 2024-06-14 12:23
---------
@summary: 认证处理
---------
@author: Lsaiah
"""

from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import HTTPException, Depends, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from settings import settings
from log import logger
from core.exceptions import AuthenticationException, AuthorizationException
# 延迟导入，避免循环依赖
# from app.system.user.models.curd.user_crud import UserCRUD

# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# JWT Bearer认证
security = HTTPBearer()


class AuthHandler:
    """认证处理类"""

    def __init__(self):
        self.secret_key = settings.SECRET_KEY
        self.algorithm = settings.ALGORITHM
        self.access_token_expire_minutes = settings.ACCESS_TOKEN_EXPIRE_MINUTES

    def verify_password(self, plain_password: str, hashed_password: str) -> bool:
        """验证密码"""
        try:
            return pwd_context.verify(plain_password, hashed_password)
        except Exception as e:
            logger.error(f"密码验证失败: {str(e)}")
            return False

    def get_password_hash(self, password: str) -> str:
        """获取密码哈希值"""
        try:
            return pwd_context.hash(password)
        except Exception as e:
            logger.error(f"密码加密失败: {str(e)}")
            raise

    def create_access_token(self, data: dict, expires_delta: Optional[timedelta] = None) -> str:
        """创建访问令牌"""
        try:
            to_encode = data.copy()
            if expires_delta:
                expire = datetime.utcnow() + expires_delta
            else:
                expire = datetime.utcnow() + timedelta(minutes=self.access_token_expire_minutes)
            
            to_encode.update({"exp": expire})
            encoded_jwt = jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
            return encoded_jwt
        except Exception as e:
            logger.error(f"创建访问令牌失败: {str(e)}")
            raise

    def create_refresh_token(self, data: dict) -> str:
        """创建刷新令牌"""
        try:
            to_encode = data.copy()
            expire = datetime.utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
            to_encode.update({"exp": expire, "type": "refresh"})
            encoded_jwt = jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
            return encoded_jwt
        except Exception as e:
            logger.error(f"创建刷新令牌失败: {str(e)}")
            raise

    def verify_token(self, token: str) -> Optional[dict]:
        """验证令牌"""
        try:
            payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
            return payload
        except JWTError as e:
            logger.error(f"令牌验证失败: {str(e)}")
            return None
        except Exception as e:
            logger.error(f"令牌处理失败: {str(e)}")
            return None

    async def get_current_user(self, credentials: HTTPAuthorizationCredentials = Depends(security)):
        """获取当前用户"""
        try:
            token = credentials.credentials
            payload = self.verify_token(token)
            
            if payload is None:
                raise AuthenticationException("无效的认证令牌")
            
            user_id: int = payload.get("sub")
            if user_id is None:
                raise AuthenticationException("令牌中缺少用户ID")
            
            # 延迟导入，避免循环依赖
            from app.system.user.models.curd.user_crud import UserCRUD
            # 从数据库获取用户信息
            user = await UserCRUD.get_user_by_id(user_id)
            if user is None:
                raise AuthenticationException("用户不存在")
            
            return user
        except (AuthenticationException, AuthorizationException):
            raise
        except Exception as e:
            logger.error(f"获取当前用户失败: {str(e)}")
            raise AuthenticationException("认证失败")

    def get_current_active_user(self):
        """获取当前活跃用户依赖"""
        async def _get_current_active_user(current_user = Depends(self.get_current_user)):
            if not current_user.is_active:
                raise AuthorizationException("用户已被禁用")
            return current_user
        return _get_current_active_user

    def get_current_superuser(self):
        """获取当前超级用户依赖"""
        async def _get_current_superuser(current_user = Depends(self.get_current_user)):
            if not current_user.is_superuser:
                raise AuthorizationException("权限不足")
            return current_user
        return _get_current_superuser

    def authenticate_user(self, username: str, password: str):
        """验证用户"""
        try:
            # 这里应该从数据库获取用户
            # 简化版本，实际项目中需要查询数据库
            return None
        except Exception as e:
            logger.error(f"用户认证失败: {str(e)}")
            return None
